﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

using ViewModels;
using System.Reactive.Linq;
using System.Windows;
using OAuthLib;
using System.Runtime.Serialization;
using RestAPICore;

using System.Threading;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using MVVMCommon.Repositories;
using MVVMCommon.ViewModels.Commands;



namespace SinaWeiboApp.ViewModels.Login
{

    public class Login_Model : ViewModelBase<Login_Model>
    {
        public Login_Model()
        {

            AllowInput = false;
            LoginCommand = new ReactiveCommand(true);
            CancelCommand = new ReactiveCommand(false);
            ConfigReactive();
            if (this.AuthTokenFactory == null)
            {
                throw new InvalidOperationException("AuthTokenFactory should not be null");
            }
            if (OAuthTokenRepository == null)
            {
                throw new InvalidOperationException("CommonSettingRepository should not be null");
            }

            var items =  OAuthTokenRepository.GetAllAsync().ConfigureAwait (false ).GetAwaiter ().GetResult ();

            SavedTokens = new ObservableCollection<AuthToken_Model>();
            SavedTokens.Insert(0, new AuthToken_Model() { UserId = "新建登录" });
            items.Values
                .Select(x => new AuthToken_Model() { SavedToken = x })
                .ToList()
                .ForEach(t => SavedTokens.Add(t));

            AllowInput = true;

        }



        /// <summary>
        /// 登陆需要用到的Token工厂
        /// </summary>
        public IUserNamePasswordAuthTokenFactory AuthTokenFactory
        {
            get;
            set;
        }

        /// <summary>
        /// 登陆需要用到的Token资料库
        /// </summary>
        public IRepository<string, AuthToken> OAuthTokenRepository
        {
            get;
            set;
        }

        public CancellationTokenSource CurrentRunningCancellationTokenSource { get; set; }
        /// <summary>
        /// 是否保存登陆凭据
        /// </summary>
        public bool SaveLoginToken
        {
            get { return _SaveLoginTokenContainerLocator(this).Value; }
            set
            {
                _SaveLoginTokenContainerLocator(this).SetValueAndTryNotify(value);
                if (value == false)
                {
                    _AutoLogin.SetValueAndTryNotify(value);
                }
            }
        }
        #region Property bool SaveLoginToken Setup

        protected PropertyContainer<bool> _SaveLoginToken;
        protected static Func<object, PropertyContainer<bool>> _SaveLoginTokenContainerLocator =
            RegisterContainerLocator<bool>(
                "SaveLoginToken",
                model =>
                    model._SaveLoginToken =
                        model._SaveLoginToken
                        ??
                        new PropertyContainer<bool>("SaveLoginToken", true));

        #endregion



        /// <summary>
        /// 是否自动登陆
        /// </summary>
        public bool AutoLogin
        {
            get { return _AutoLoginContainerLocator(this).Value; }
            set { _AutoLoginContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property bool AutoLogin Setup

        protected PropertyContainer<bool> _AutoLogin;
        protected static Func<object, PropertyContainer<bool>> _AutoLoginContainerLocator =
            RegisterContainerLocator<bool>(
                "AutoLogin",
                model =>
                    model._AutoLogin =
                        model._AutoLogin
                        ??
                        new PropertyContainer<bool>("AutoLogin", true));

        #endregion



        /// <summary>
        /// 登陆名
        /// </summary>
        public string UserName
        {
            get { return _UserNameContainerLocator(this).Value; }
            set { _UserNameContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property string UserName Setup

        protected PropertyContainer<string> _UserName;
        protected static Func<object, PropertyContainer<string>> _UserNameContainerLocator =
            RegisterContainerLocator<string>(
                "UserName",
                model =>
                    model._UserName =
                        model._UserName
                        ??
                        new PropertyContainer<string>("UserName"));

        #endregion



        /// <summary>
        /// 密码
        /// </summary>
        public string Password
        {
            get { return _PasswordContainerLocator(this).Value; }
            set { _PasswordContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property string Password Setup

        protected PropertyContainer<string> _Password;
        protected static Func<object, PropertyContainer<string>> _PasswordContainerLocator =
            RegisterContainerLocator<string>(
                "Password",
                model =>
                    model._Password =
                        model._Password
                        ??
                        new PropertyContainer<string>("Password"));

        #endregion




        /// <summary>
        /// 当前界面是否允许输入
        /// </summary>
        public bool AllowInput
        {
            get { return _AllowInputContainerLocator(this).Value; }
            protected set { _AllowInputContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property bool AllowInput Setup

        protected PropertyContainer<bool> _AllowInput;
        protected static Func<object, PropertyContainer<bool>> _AllowInputContainerLocator =
            RegisterContainerLocator<bool>(
                "AllowInput",
                model =>
                    model._AllowInput =
                        model._AllowInput
                        ??
                        new PropertyContainer<bool>("AllowInput", true));

        #endregion



        /// <summary>
        /// 当前界面是否在等待响应
        /// </summary>
        public bool IsWaitingForResponse
        {
            get { return _IsWaitingForResponseContainerLocator(this).Value; }
            protected set { _IsWaitingForResponseContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property bool IsWaitingForResponse Setup

        protected PropertyContainer<bool> _IsWaitingForResponse;
        protected static Func<object, PropertyContainer<bool>> _IsWaitingForResponseContainerLocator =
            RegisterContainerLocator<bool>(
                "IsWaitingForResponse",
                model =>
                    model._IsWaitingForResponse =
                        model._IsWaitingForResponse
                        ??
                        new PropertyContainer<bool>("IsWaitingForResponse"));

        #endregion

        /// <summary>
        /// 需要持久化的验证数据
        /// </summary>

        public AuthToken AuthToken
        {
            get { return _AuthTokenContainerLocator(this).Value; }
            set { _AuthTokenContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property AuthToken AuthToken Setup
        protected PropertyContainer<AuthToken> _AuthToken;
        protected static Func<object, PropertyContainer<AuthToken>> _AuthTokenContainerLocator =
            RegisterContainerLocator<AuthToken>(
                "AuthToken",
                model =>
                    model._AuthToken =
                        model._AuthToken
                        ??
                        new PropertyContainer<AuthToken>("AuthToken"));
        #endregion





        public ObservableCollection<AuthToken_Model> SavedTokens
        {
            get { return _SavedTokensContainerLocator(this).Value; }
            set { _SavedTokensContainerLocator(this).SetValueAndTryNotify(value); }
        }
        #region Property ObservableCollection<AuthToken_Model> SavedTokens Setup
        protected PropertyContainer<ObservableCollection<AuthToken_Model>> _SavedTokens;
        protected static Func<object, PropertyContainer<ObservableCollection<AuthToken_Model>>> _SavedTokensContainerLocator =
            RegisterContainerLocator<ObservableCollection<AuthToken_Model>>(
                "SavedTokens",
                model =>
                    model._SavedTokens =
                        model._SavedTokens
                        ??
                        new PropertyContainer<ObservableCollection<AuthToken_Model>>("SavedTokens"));
        #endregion







        private void ConfigReactive()
        {

            //UseCase1.1:按下Login按钮则进行通信，显示通信中，终断或完成则取消显示
            //按照登陆名保存在Repository中
             LoginCommand
                .Where(_ => DateTime.Now.Hour > 5)
                .Subscribe(
                    async p =>
                    {
                        try
                        {
                            CurrentRunningCancellationTokenSource = new CancellationTokenSource();
                            _Error.SetValueAndTryNotify(string.Empty);
                            this.IsWaitingForResponse = true;
                            AuthTokenFactory.UserName = UserName;
                            AuthTokenFactory.Password = Password;
                            var res = await AuthTokenFactory.CreateTokenAsync(CurrentRunningCancellationTokenSource.Token);
                            await OAuthTokenRepository.SetOrUpdateByKeyAsync(UserName.ToLower(), res);
                        }
                        catch (Exception ex)
                        {
                            _Error.SetValueAndTryNotify(ex.Message);

                        }
                        finally
                        {
                            this.IsWaitingForResponse = false;
                        }
                    }
                )
                .RegisterDispose (this);

            //UseCase1.2: 当用户名密码有任意为空时，或者正在等待通信回应时，Login按钮不可以按下
            var _loginCanExecute
                = _UserName.AsObservable()
                .Select(_ => 0)
                .Merge(_Password.AsObservable().Select(_ => 0))
                .Merge(_IsWaitingForResponse.AsObservable().Select(_ => 0))
                .Select(_ => _UserName.Value.Length > 0 && _Password.Value.Length > 0 && (!_IsWaitingForResponse.Value));
            _loginCanExecute.Subscribe(LoginCommand).RegisterDispose(this);


            //UseCase2.1:按下取消按钮则取消正在进行的Login
            CancelCommand.Subscribe(_ => CurrentRunningCancellationTokenSource.Cancel())
                .RegisterDispose(this);

            //UseCase2.1:只有正在等待通信回应时，Login按钮才可以按下
            _IsWaitingForResponse
                .AsObservable()
                .Where(arg => arg.NewValue)
                .Select(arg => arg.NewValue)
                .Subscribe(CancelCommand)
                .RegisterDispose(this);

        }





        public ReactiveCommand LoginCommand { get; private set; }
        public ReactiveCommand CancelCommand { get; private set; }

       
    }
}
